﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System.Collections.Generic;
using System.Linq;

namespace FinPlusCommon
{
    public class Permissions
    {
        private readonly IFunctions _permissions;
        private class User: Dictionary<string, Name>{ }
        private class Name: Dictionary<string, ItemName>{ }
        private class ItemName: Dictionary<string, ItemValue>{ }
        private class ItemValue : Dictionary<string, Permission> { }
        private User _index = new User();
        private enum Params { FunctionName, Permission, User, Name, ItemName, ItemValue, CanRead, CanWrite }

        //construct
        public Permissions(IFunctions funcs)
        {
            _permissions = funcs;
            _permissions.FuncUpdate += Permission_Update;

            lock (_permissions)
            {
                foreach (var func in _permissions.Values.Where(f => f[Params.FunctionName.ToString()].Equals(Params.Permission.ToString())))
                    Add(func);
            }
        }

        private void Add(IFunction func)
        {
            var user = func[Params.User.ToString()].ToString();
            var name = func[Params.Name.ToString()].ToString();
            var itemName = func[Params.ItemName.ToString()].ToString();
            var itemValue = func[Params.ItemValue.ToString()].ToString();
            var perm = new Permission((bool)func.Value(Params.CanRead.ToString()), (bool)func.Value(Params.CanWrite.ToString()), itemValue.Equals("*"));

            if (!_index.ContainsKey(user)) _index[user] = new Name();
            
            if (!_index[user].ContainsKey(name)) _index[user][name] = new ItemName();

            if (!_index[user][name].ContainsKey(itemName)) _index[user][name][itemName] = new ItemValue();
            
            _index[user][name][itemName][itemValue] = perm;
        }

        //public
        public Permission Get(string user, string name, string itemName, string itemValue)
        {
            try
            {
                if (_index.ContainsKey(user))
                {
                    var u = _index[user];
                    if (u.ContainsKey(name))
                    {
                        var n = u[name];
                        if (n.ContainsKey(itemName))
                        {
                            var i = n[itemName];
                            if (i.ContainsKey(itemValue))
                                return i[itemValue];
                            else if (i.ContainsKey("*"))
                                return i["*"];
                        }
                    }
                }

                return new Permission(false, false);
            }
            catch
            {
                return new Permission(false, false);
            }
        }

        //event
        private void Permission_Update(object s, ItemEventArgs a)
        {
            try
            {
                var func = (IFunction)s;

                if (!func[Params.FunctionName.ToString()].ToString().Equals(Params.Permission.ToString())) return;
              
                lock (_permissions)
                {
                    if (a.ChangeType == ChangeType.Removed)
                        _index[func[Params.User.ToString()].ToString()][func[Params.Name.ToString()].ToString()][func[Params.ItemName.ToString()].ToString()].Remove(func[Params.ItemValue.ToString()].ToString());
                    else if (a.ChangeType == ChangeType.New || a.ChangeType == ChangeType.Altered)
                        Add(func);
                }
            }
            catch
            {
                //TODO
            }
        }
    }

    public class Permission
    {
        public bool CanRead { get; private set; }
        public bool CanWrite { get; private set; }
        public bool Overwrite { get; private set; }

        public Permission(bool canRead, bool canWrite, bool ovewrite = false)
        {
            CanRead = canRead;
            CanWrite = canRead ? canWrite : false;
            Overwrite = ovewrite;
        }
        
        //construct
        public static Permission operator +(Permission p1, Permission p2)
        {
            if (p1.Overwrite) 
                return p1;
            return new Permission(p1.CanRead && p2.CanRead ? true : false, p1.CanWrite && p2.CanWrite ? true : false, p2.Overwrite);
        }

        //public
        public override string ToString()
        {
            return string.Format("CanRead {0} CanWrite {1}", CanRead.ToString(), CanWrite.ToString());
        }
    }
}

